﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

using DAL.HashAndSalt;
using System.Data.Entity.Validation;

namespace DAL
{
    public class DALCustomer : IDALCustomer, IDisposable
    {
        private CarBatteryEntities context;
        private bool disposed = false;

        static PasswordManager pwdManager = new PasswordManager();

        public DALCustomer(CarBatteryEntities context)
        {
            this.context = context;
        }

        public IEnumerable<Customer> GetCustomers()
        {
            return context.Customer.ToList();
        }

        public Customer GetCustomerByID(int customerID)
        {
            return context.Customer.Find(customerID);
        }

        public Customer GetCustomerByName(string customerName)
        {
            return context.Customer.FirstOrDefault(x => x.name.Equals(customerName));
        }

        public Customer GetCustomerByUserName(string customerUsername)
        {
            return context.Customer.FirstOrDefault(x => x.username.Equals(customerUsername));
        }

        public Customer CheckLoginCredentials(string username, string password)
        {
            Customer cust = GetCustomerByUserName(username);

            return cust == null ? null : (pwdManager.IsPasswordMatch(password, cust.salt, cust.password) ? cust : null);
        }

        public void InsertCustomer(Customer customer)
        {
            string salt = SaltGenerator.GetSaltString();

            customer.password = pwdManager.GeneratePasswordHash(customer.password, out salt);
            customer.salt = salt;

            context.Customer.Add(customer);
        }

        public void DeleteCustomer(int customerID)
        {
            context.Customer.Remove(GetCustomerByID(customerID));
        }

        public void UpdateCustomer(Customer customer)
        {
            string salt = customer.salt;
            customer.password = pwdManager.GeneratePasswordHash(customer.password, out salt);
            context.Entry(customer).State = EntityState.Modified;
        }

        public int Save()
        {
            try
            {
                return context.SaveChanges();
            }
            catch (DbEntityValidationException e)
            {
                foreach (var eve in e.EntityValidationErrors)
                {
                    Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State);

                    foreach (var ve in eve.ValidationErrors)
                        Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage);
                }

                throw;
            }
        }

        public virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                    context.Dispose();

                this.disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private string GetMD5Hash(string input)
        {
            using (MD5 md5Hash = MD5.Create())
            {
                byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

                StringBuilder sBuilder = new StringBuilder();

                for (int i = 0; i < data.Length; i++)
                    sBuilder.Append(data[i].ToString("x2"));

                return sBuilder.ToString();
            }
        }
    }
}